/*
 * 本模块基于set（红黑树）数据结构，提供会话级定时器。
 * 会话级定时器仅支持一次性定时器 ，不支持循环定时器。
 * 为了方便业务使用定时器，本模块内部定义了 thread_local SessionTimer g_timer来管理定时器，业务不需要自己定义SessionTimer对象。
 * 可以直接调用下面的接口
 * session_timer_node_t session_timer_add_timer(time_t msec, session_timer_cb_t func, std::shared_ptr<void> arg);
 * bool session_timer_del_timer(session_timer_node_t &node);
 * bool session_timer_check_timer();
 * int session_timer_get_timer_num();
 * 为了提高性能，会话级定时器内部没有锁机制，不是线程安全的，不支持多线程并发使用。
 * 业务如需多线程使用，需要自己定义SessionTimer g_timer，并在调用SessionTimer类接口时进行必要的互斥保护。
 */
#pragma once

#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <set>
#include <memory>
#include <stdlib.h>
#include <stdio.h>

namespace secsmart_tcpip
{
struct session_timer_base_node {
    time_t expires; //过期时间
    int64_t id; // 定时器id
};
using session_timer_cb_t = std::function<void(const struct session_timer_node &node)>;
typedef struct session_timer_node : public session_timer_base_node
{
    // time_t expires; //过期时间
    // int64_t id; // 定时器id
    time_t gap; // 定时器超时间隔
    session_timer_cb_t func; // 定时器回调函数
    std::shared_ptr<void> arg; // 定时器回调函数的参数
} session_timer_node_t;

static inline bool operator<(const session_timer_node_t &lhd, const session_timer_node_t &rhd)
{
    if (lhd.expires < rhd.expires)
        return true;
    else if (lhd.expires > rhd.expires)
        return false;
    return lhd.id < rhd.id; //此时超时时间相同，后插入放在红黑树右边，后执行
}

// 定时器精度为毫秒，为了高性能，该定时器不支持多线程并发, 在 
class SessionTimer
{ 
public:
    // 获取当前时间， 系统启动到当前的时间，毫秒
    static time_t get_tick()
    {
        struct timespec time_now;
	    clock_gettime(CLOCK_MONOTONIC, &time_now); // 精度本身可以达到ns
	    return (time_t)(time_now.tv_sec*1000 + time_now.tv_nsec/1000000); //使用毫秒
    }

    int64_t get_id()
    {
        return ++m_node_id;
    }
 
    // 添加定时器
    session_timer_node_t add_timer(time_t msec, session_timer_cb_t func, std::shared_ptr<void> arg)
    {
        session_timer_node_t node;
        node.expires = get_tick() + msec;
        node.id = get_id();
        node.gap = msec;
        node.func = func;
        node.arg = arg;
        //添加数据到某个结构中
        m_timermap.insert(node);
        return node;
    }
    
    // 删除定时器
    bool del_timer(session_timer_node_t &node)
    {
        //删除制定ID的任务
        auto iter = m_timermap.find(node);
        if (iter != m_timermap.end()) {
            m_timermap.erase(iter);
            return true;
        }
        return false;
    }
 
    // 检查定时器是否超时，超时则执行超时函数
    bool check_timer()
    {
        //先找到某个数据结构的最小时间节点，与当前时间比较，若当前时间大于等于最小时间节点，则此间点被触发，不符合条件删除
        auto iter = m_timermap.begin();
        if ((iter != m_timermap.end()) && (iter->expires <= get_tick())) {
            // 支持定时器回调
            iter->func(*iter);

            // 删除当前定时器节点
            m_timermap.erase(iter);

            return true;
        }
        return false;
    }

    // 最近超时时间
    time_t time_to_expire()
    {
        auto iter = m_timermap.begin();
        if (iter == m_timermap.end()) {
            return -1;
        }
        time_t diss = iter->expires - get_tick();
        return diss > 0 ? diss : 0;
    }

    int get_timer_node_num()
    {
        return (int)m_timermap.size();
    }
 
private:
    int64_t m_node_id = 0;
    std::set<session_timer_node_t, std::less<session_timer_node_t>> m_timermap;
};

/**
 * @brief 添加定时器
 * @param msec 定时器周期
 * @param func 定时器回调函数
 * @param arg 定时器回调函数的参数
 * @return 生成的定时器节点
 */
session_timer_node_t session_timer_add_timer(time_t msec, session_timer_cb_t func, std::shared_ptr<void> arg);

/**
 * @brief 删除定时器
 * @param node 待删除的定时器节点
 * @return 删除成功返回true，查不到节点返回false
 */
bool session_timer_del_timer(session_timer_node_t &node);

/**
 * @brief 检查定时器是否超时，如果超时，则执行定时器回调函数。
 * @return true，有定时器超时；false，没有定时器超时
 */
bool session_timer_check_timer();

/**
 * @brief 获取当前定时器的数目
 * @return 当前定时器的数目
 */
int session_timer_get_timer_num();

/**
 * @brief 最近定时器的超时间隔时间
 * @return 
 */
time_t session_time_to_expire(); 

}